<!-- CubeBarChart.vue 2023/5/18 @wanghaoran -->
<!-- 立方体柱状图 -->
<template>
  <div class="cube-bar-chart" ref="chartRef"></div>
</template>

<script>
export default {
  name: 'CubeBarChart'
}
</script>

<script setup>
import { onMounted, onUnmounted, ref, watchEffect } from 'vue'
import * as echarts from 'echarts'
import { deepMergeObjects, generateLighterColors } from '../../../utils/objectUtils'

const props = defineProps({
  // x 轴，图表分类
  category: {
    type: Array,
    default: () => {
      return []
    }
  },
  // y 轴, 图表值
  values: {
    type: Array,
    default: function () {
      return []
    }
  },
  // 标题
  title: {
    type: String,
    default: ``
  },
  // 主题色
  themeColor: {
    type: String,
    default: `rgba(29, 67, 243, 1)`,
  },
  // 是否开启比率，需要最大值
  isRate: {
    type: Boolean,
    default: false
  },
  // 最大值
  max: {
    type: [String, Number],
    default: 100,
  },
  // echart 的配置项 options 与默认配置合并
  chartOptions: {
    type: Object,
    default: function () {
      return {}
    }
  }
})
// echart5 版本 echart实例不能是vue3的响应式实例，会影响tooltip
let chart = null
const chartRef = ref(null)
// 绘制左侧面
const CubeLeft = echarts.graphic.extendShape({
  shape: {
    x: 0,
    y: 0
  },
  buildPath: function (ctx, shape) {
    // 会canvas的应该都能看得懂，shape是从custom传入的
    const xAxisPoint = shape.xAxisPoint
    const c0 = [shape.x, shape.y]
    const c1 = [shape.x - 13, shape.y - 13]
    const c2 = [xAxisPoint[0] - 13, xAxisPoint[1] - 13]
    const c3 = [xAxisPoint[0], xAxisPoint[1]]
    ctx.moveTo(c0[0], c0[1]).lineTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).closePath()
  }
})
// 绘制右侧面
const CubeRight = echarts.graphic.extendShape({
  shape: {
    x: 0,
    y: 0
  },
  buildPath: function (ctx, shape) {
    const xAxisPoint = shape.xAxisPoint
    const c1 = [shape.x, shape.y]
    const c2 = [xAxisPoint[0], xAxisPoint[1]]
    const c3 = [xAxisPoint[0] + 18, xAxisPoint[1] - 9]
    const c4 = [shape.x + 18, shape.y - 9]
    ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath()
  }
})
// 绘制顶面
const CubeTop = echarts.graphic.extendShape({
  shape: {
    x: 0,
    y: 0
  },
  buildPath: function (ctx, shape) {
    const c1 = [shape.x, shape.y]
    const c2 = [shape.x + 18, shape.y - 9]
    const c3 = [shape.x + 5, shape.y - 22]
    const c4 = [shape.x - 13, shape.y - 13]
    ctx.moveTo(c1[0], c1[1]).lineTo(c2[0], c2[1]).lineTo(c3[0], c3[1]).lineTo(c4[0], c4[1]).closePath()
  }
})
// 注册三个面图形
echarts.graphic.registerShape('CubeLeft', CubeLeft)
echarts.graphic.registerShape('CubeRight', CubeRight)
echarts.graphic.registerShape('CubeTop', CubeTop)

// 根据主题色生成颜色
let colorList = generateLighterColors(props.themeColor)

const MAX = props.category.map(e => props.max)

const options = {
  // backgroundColor: "#012366",
  title: {
    text: props.title,
  },
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    },
    formatter: function (params, ticket, callback) {
      let item
      if (props.isRate) {
        item = params[1]
      } else {
        item = params[0]
      }
      return item.name + ' : ' + item.value

    }
  },
  grid: {
    top: '20%',
    left: '5%',
    right: '2%',
    bottom: '20%',
    // containLabel: true
  },
  xAxis: {
    type: 'category',
    data: props.category,
    axisLine: {
      show: false,
      lineStyle: {
        color: '#7f7f7f'
      }
    },
    offset: 10,
    axisTick: {
      show: false,
      length: 9,
      alignWithLabel: true,
      lineStyle: {
        color: '#7DFFFD'
      }
    },
    axisLabel: {
      show: true,
      fontSize: 14
    },
  },
  yAxis: {
    type: 'value',
    axisLine: {
      show: false,
      lineStyle: {
        color: '#7f7f7f'
      }
    },
    splitLine: {
      show: true
    },
    axisTick: {
      show: false
    },
    axisLabel: {
      show: true,
      fontSize: 14
    },
    boundaryGap: ['0%', '0%']
  },
  series: [
    {
      type: 'custom',
      renderItem: function (params, api) {
        const location = api.coord([api.value(0), api.value(1)])
        return {
          type: 'group',
          children: [
            {
              type: 'CubeLeft',
              shape: {
                api,
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                // fill: 'rgba(47,102,192,.27)',
                fill: colorList[6]
              }
            },
            {
              type: 'CubeRight',
              shape: {
                api,
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                // fill: 'rgba(59,128,226,.27)',
                fill: colorList[6]
              }
            },
            {
              type: 'CubeTop',
              shape: {
                api,
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                // fill: 'rgba(72,156,221,.27)',
                fill: colorList[5],
              }
            }
          ]
        }
      },
      data: props.isRate ? props.category.map(e => props.max) : []
    },
    {
      type: 'custom',
      renderItem: (params, api) => {
        const location = api.coord([api.value(0), api.value(1)])
        var color = api.value(1) > 2000 ? 'red' : new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
          offset: 0,
          // color: 'rgba(67,102,243,1)'
          color: colorList[1]
        },
          {
            offset: 1,
            // color: 'rgba(29,67,243,1)'
            color: colorList[0]
          }
        ])
        return {
          type: 'group',
          children: [
            {
              type: 'CubeLeft',
              shape: {
                api,
                xValue: api.value(0),
                yValue: api.value(1),
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                fill: color
              }
            },
            {
              type: 'CubeRight',
              shape: {
                api,
                xValue: api.value(0),
                yValue: api.value(1),
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                fill: color
              }
            },
            {
              type: 'CubeTop',
              shape: {
                api,
                xValue: api.value(0),
                yValue: api.value(1),
                x: location[0],
                y: location[1],
                xAxisPoint: api.coord([api.value(0), 0])
              },
              style: {
                fill: color
              }
            }
          ]
        }
      },
      data: props.values,
    },
    {
      type: 'bar',
      label: {
        normal: {
          show: true,
          position: 'top',

          fontSize: 16,
          color: '#7f7f7f',
          offset: [2, -25]
        }
      },
      itemStyle: {
        color: 'transparent'
      },
      tooltip: {},
      data: props.isRate ? props.category.map(e => props.max) : []
    }
  ]
}

const setOption = (option = options) => {
  option.xAxis.data = props.category
  option.title.text = props.title
  option.series[1].data = props.values
  if (props.isRate) {
    option.series[2].data = props.category.map(e => props.max)
    option.series[0].data = props.category.map(e => props.max)
  }else {
    option.series[2].data = []
    option.series[0].data = []
  }
  colorList = generateLighterColors(props.themeColor)
  const opt = deepMergeObjects(option, props.chartOptions)
  if (chart) {
    chart.setOption(opt, true)
  }
}
const initChart = () => {
  chart = echarts.init(chartRef.value)
}

onMounted(() => {
  initChart()
  setOption()
  watchEffect(() => {
    setOption()
  }, {})
  const resizeHandler = () => {
    if (chart != null) {
      try {
        setOption()
        chart.resize()
      } catch (error) {
        console.error('Resize error:', error)
      }
    }
  }
  window.addEventListener('resize', resizeHandler)

  // 组件卸载时移除事件监听器
  onUnmounted(() => {
    window.removeEventListener('resize', resizeHandler)
    if (chart != null) {
      chart.dispose()
    }
  })
})


</script>

<style scoped>
.cube-bar-chart {
  position: absolute;
  height: 100%;
  width: 100%;
}
</style>
